package com.hainan.bike.common.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;

/**
 * 数据库工具类，主要包含构造SQL语句时使用的一些公用方法
 * @author huang
 * @version 1.0
 */
public class DbUtil
{

   private static Logger logger = Logger.getLogger(DbUtil.class);

   /**
    * 当字符串的值为null或""时，返回"null";否则为'插入值'。
    * 注意：为了允许往数据库插入单引号，需要把单引号转换为两个单引号。
    * @param fieldValue
    * @return String
    */
   public static String fieldValue(String fieldValue)
   {
      if(fieldValue == null || fieldValue.equals("")) {
         return "''";
      } else {
         return("'" + fieldValue.trim().replaceAll("\'", "\'\'") + "'");
      }
   }

   /**
    * 往数据库的表中插入double值。
    * @param fieldValue
    * @return double
    */
   public static double fieldValue(double fieldValue)
   {
      return fieldValue;
   }

   /**
    * 往数据库的表中插入double值。
    * @param fieldValue
    * @return double
    */
   public static double fieldValue(Double fieldValue)
   {
      return fieldValue.doubleValue();
   }

   /**
    * 往数据库的表中插入float值。
    * @param fieldValue
    * @return
    */
   public static float fieldValue(float fieldValue)
   {
      return fieldValue;
   }

   /**
    * 往数据库的表中插入float值。
    * @param fieldValue
    * @return
    */
   public static float fieldValue(Float fieldValue)
   {
      return fieldValue.floatValue();
   }

   /**
    * 往数据库的表中插入int值。
    * @param fieldValue
    * @return
    */
   public static int fieldValue(int fieldValue)
   {
      return fieldValue;
   }

   /**
    * 往数据库的表中插入int值。
    * @param fieldValue
    * @return
    */
   public static int fieldValue(Integer fieldValue)
   {
      return fieldValue.intValue();
   }

   /**
    * 往数据库的表中插入long型数值。
    * @param fieldValue
    * @return
    */
   public static long fieldValue(long fieldValue)
   {
      return fieldValue;
   }

   /**
    * 往数据库的表中插入long型数值。
    * @param fieldValue
    * @return
    */
   public static long fieldValue(Long fieldValue)
   {
      return fieldValue.longValue();
   }

   /**
    * 关闭记录集
    * @param rs
    */
   public static void closeRs(ResultSet rs)
   {
      try {
         if(rs != null) {
            rs.close();
            rs = null;
         }
      } catch(SQLException e) {
         e.printStackTrace();
      }
   }

   /**
    * 关闭数据库连接
    * @param conn
    */
   public static void closeConn(Connection conn)
   {
      try {
         if(conn != null) {
            conn.close();
            conn = null;
         }
      } catch(SQLException e) {
         e.printStackTrace();
      }
   }

   /**
    * 关闭Statement
    * @param stmt
    * @roseuid 4185D8990128
    */
   public static void closeStmt(Statement stmt)
   {
      try {
         if(stmt != null) {
            stmt.close();
            stmt = null;
         }
      } catch(SQLException e) {
         e.printStackTrace();
      }
   }

   /**
    * 装载JDBC驱动程序
    * @param driverClassName
    * @return
    */
   public static boolean loadJDBCDriver(String driverClassName)
   {
      try {
         Class.forName(driverClassName).newInstance();
         return true;
      } catch(ClassNotFoundException e) {
         return false;
      } catch(IllegalAccessException e) {
         return true;
      } catch(InstantiationException e) {
         return false;
      } catch(Throwable t) {
         return false;
      }
   }

   /**
    * 关闭所有对象
    * @param rs
    * @param stmt
    * @param conn
    */
   public static void close(ResultSet rs, Statement stmt, Connection conn)
   {
      closeRs(rs);
      closeStmt(stmt);
      closeConn(conn);
   }

   /**
    * 为sql赋参数值
    * @param stmt
    * @param params 参数值数组，数组元素顺序要和stmt里参数顺序保持一致
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static void fillStatement(PreparedStatement stmt, Object[] params) throws
       SQLException
   {
      if(params == null) {
         return;
      }

      for(int i = 0; i < params.length; i++) {
         if(params[i] != null) {
            stmt.setObject(i + 1, params[i]);
         } else {
            stmt.setNull(i + 1, Types.VARCHAR);
         }
      }
   }

   /**
    * 接受一个对象，用对象里的属性值填充stmt里的参数
    * @param stmt
    * @param paramObj
    * @param paramObjFields 要用到的对象属性，
    * 数组元素顺序要和stmt里参数顺序保持一致。通过数组元素取得对象的属性值。
    * @throws java.lang.Exception
    */
   public static void fillStatement(PreparedStatement stmt, Object paramObj,
                                    String[] paramObjFields) throws Exception
   {
      StringBuffer debugBuf = new StringBuffer();
      Object[] params = new Object[paramObjFields.length];
      for(int i = 0; i < paramObjFields.length; i++) {
    	 try{ 
    		 params[i] = PropertyUtils.getSimpleProperty(paramObj, paramObjFields[i]);
    	 }catch(NoSuchMethodException e){
    		 params[i] = null;
    	 }
    	 if (logger.isDebugEnabled()){
    		 debugBuf.append(paramObjFields[i]+"="+params[i]+",") ;
    	 }
      }
      if (logger.isDebugEnabled()){
         logger.debug("VO����"+paramObj+":["+debugBuf+"]") ;
      }

      fillStatement(stmt, params);
   }

   /**
    * 构造符合PreparedStatment格式要求的插入SQL语句
    * <pre>
    * String[] insertColumnNames = {"col1","col2","col3"} ;
    * String insertSql = buildPrepareInsertSQL("TEST",insertColumnNames)
    * insertSql的值为：insert into TEST(col1,col2,col3) values(?,?,?)
    * </pre>
    * @param tableName 表名
    * @param 要插入字段值的字段名数组
    * @param insertColumnNames
    * @return
    */
   public static String buildInsertSQL(String tableName,
                                       String[] insertColumnNames)
   {
      StringBuffer insertSQL = new StringBuffer("insert into ");

      insertSQL.append(tableName);
      insertSQL.append(" (")
          .append(getCloumnNamesStr(insertColumnNames)).append(")");

      StringBuffer paramBuf = new StringBuffer("");
      for(int i = 0; i < insertColumnNames.length; i++) {
         paramBuf.append("?");
         if(i != insertColumnNames.length - 1) {
            paramBuf.append(",");
         }
      }
      insertSQL.append(" values(").append(paramBuf).append(")");

      if(logger.isDebugEnabled()) {
         logger.debug("构造插入SQL语句：" + insertSQL);
      }

      return insertSQL.toString();
   }


   /**
    * 构造符合PreparedStatment格式要求的修改SQL语句。
    * 注意：只能构造简单的无条件修改语句或者条件之间用"and"连接，比较运算符用"="的修改
    * 语句。
    * 不支持构造其它形式的修改语句。
    * <pre>
    * String[] updateColumnNames = {"col1","col2","col3"} ;
    * String[] whereColumnNames = {"col4"} ;
    * String updateSql =
    * buildPrepareUpdateSQL("TEST",updateColumnNames,whereColumnNames)
    * updateSql的值为：update TEST set col1=?,col2=?,col3=? where col4=?
    * </pre>
    * @param tableName 表名
    * @param updateColumnNames 要修改的字段名数组
    * @param whereColumnNames
    * 条件字段名数组，如果为null或者数组长度为0则返回没有条件的修改语句
    * @param whereColumnNames
    * @return
    */
   public static String buildSimpleUpdateSQL(String tableName,
                                             String[] updateColumnNames,
                                             String[] whereColumnNames)
   {
      StringBuffer updateSQL = new StringBuffer("update ").append(tableName).
          append(" set ");
      for(int i = 0; i < updateColumnNames.length; i++) {
         updateSQL.append(updateColumnNames[i]).append("=?");
         if(i != updateColumnNames.length - 1) {
            updateSQL.append(",");
         }
      }
      if(whereColumnNames != null || whereColumnNames.length != 0) {
         updateSQL.append(" where 1=1");
         for(int i = 0; i < whereColumnNames.length; i++) {
            updateSQL.append(" and ").append(whereColumnNames[i]).append("=?");
         }
      }

      if(logger.isDebugEnabled()) {
         logger.debug("构造修改SQL语句：" + updateSQL);
      }

      return updateSQL.toString();
   }

   /**
    * 把要插入字段数组转换为字符串，形如 column1,column2
    * @param insertColumnNames
    * @return
    */
   private static String getCloumnNamesStr(String[] insertColumnNames)
   {
      StringBuffer columnNameBuf = new StringBuffer("");
      if(insertColumnNames != null && insertColumnNames.length != 0) {
         for(int i = 0; i < insertColumnNames.length; i++) {
            columnNameBuf.append(insertColumnNames[i]);
            if(i != insertColumnNames.length - 1) {
               columnNameBuf.append(",");
            }
         }
      }

      return columnNameBuf.toString();
   }

   /**
    * 构造符合PreparedStatment格式要求的删除SQL语句。
    * 注意：只能构造简单的无条件删除语句或者条件之间用"and"连接，比较运算符用"="的删除
    * 语句。不支持构造其它形式的删除语句。
    * <pre>
    * String[] whereColumnNames = {"col1","col2"} ;
    * String deleteSql = DbUtil.buildDeleteSQL("TEST",whereColumnNames)
    * deleteSql的值为：delete from TEST where col1=? and col2=?
    * </pre>
    * @param tableName - 要删除记录的表名
    * @param whereColumnNames - 删除条件字段数组，用于构造删除where子句
    * @return java.lang.String
    */
   public static String buildSimpleDeleteSQL(String tableName,
                                             String[] whereColumnNames)
   {
      StringBuffer updateSQL = new StringBuffer("delete from ").append(
          tableName);

      if(whereColumnNames != null || whereColumnNames.length != 0) {
         updateSQL.append(" where 1=1");
         for(int i = 0; i < whereColumnNames.length; i++) {
            updateSQL.append(" and ").append(whereColumnNames[i]).append("=?");
         }
      }

      if(logger.isDebugEnabled()) {
         logger.debug("构造删除SQL语句：" + updateSQL);
      }

      return updateSQL.toString();
   }

   /**
    * 把数据库字段名称转换为标准的Java属性名称。
    * @param fieldName - 数据库字段名称。
    * @return java.lang.String
    * @roseuid 41A695860261
    */
   public static String fieldNameToPropertyName(String fieldName)
   {
      String tempStr = fieldName.toLowerCase();
      String[] splitNames = tempStr.split("_");
      StringBuffer result = new StringBuffer();

      for(int i = 0; i < splitNames.length; i++) {
         if(i == 0) {
            result.append(splitNames[0]);
         } else {
            String firstChar = splitNames[i].charAt(0) + "";
            result.append(firstChar.toUpperCase())
                .append(splitNames[i].substring(1));
         }
      }

      return result.toString();
   }

   /**
    * 把数组中的数据库字段名全部转换为标准的Java属性名称。
    * @param fieldNames - 数据库字段名数组。
    * @return java.lang.String[]
    */
   public static String[] fieldNameToPropertyName(String[] fieldNames)
   {
      String[] results = new String[fieldNames.length];

      for(int i = 0; i < fieldNames.length; i++) {
         results[i] = fieldNameToPropertyName(fieldNames[i]);
      }

      return results;
   }
}
